package com.codi.api.controller.h5;

import com.codi.api.security.UserUtil;
import com.codi.api.validation.PortfolioValidation;
import com.codi.base.cache.CacheUtil;
import com.codi.base.domain.BaseResult;
import com.codi.base.exception.BaseAppException;
import com.codi.base.log.annotation.Loggable;
import com.codi.base.util.EqualsUtil;
import com.codi.base.util.ExceptionUtil;
import com.codi.base.util.StringUtil;
import com.codi.base.web.RequestUtils;
import com.codi.bus.constant.GlobalConstant;
import com.codi.bus.constant.PayTypeConst;
import com.codi.bus.core.resultModel.DividendApplyResult;
import com.codi.bus.core.resultModel.PTradingRecordListResult;
import com.codi.bus.core.resultModel.PortfolioApplyListResult;
import com.codi.bus.core.resultModel.PortfolioTradeResult;
import com.codi.bus.core.service.*;
import com.codi.bus.core.vo.PortfolioTradeBuyVo;
import com.codi.bus.core.vo.PortfolioTradeUndoVo;
import com.codi.bus.core.vo.SessionVo;
import com.codi.message.constant.ErrorConst;
import com.codi.message.constant.ErrorConstant;
import com.codi.message.util.MessageUtil;
import com.google.common.base.Strings;
import com.google.common.collect.Maps;
import lombok.NonNull;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * @Author: wzh
 * @Description: 基金组合相关控制类
 * @Date:2018/3/8 13:46
 */
@RestController
@Slf4j
@RequestMapping("h5/portfolio")
public class H5PortfolioController {
    @Autowired
    private FundCombinationService fundCombinationService;
    @Autowired
    private RedisTemplate<String, String> stringRedisTemplate;
    @Autowired
    private FundCombinationHistoryService fundCombinationHistoryService;
    @Autowired
    private ApplyRecordService applyRecordService;
    @Autowired
    private FundWarehouseTransferService fundWarehouseTransferService;
    @Autowired
    private PortfolioService portfolioService;
    @Autowired
    private QueryService queryService;
    @Autowired
    private DividendApplyService dividendApplyQuery;
    @Autowired
    private PaymentService paymentService;
    @Autowired
    private PortfolioValidation portfolioValidation;

    /**
     * 首页组合列表
     *
     * @return
     */
    @GetMapping("portfolioList")
    @Loggable
    public BaseResult list() {
        return BaseResult.success(fundCombinationService.queryPortfolios());
    }

    /**
     * 组合详情
     *
     * @param combinationCode
     * @return
     */
    @GetMapping("detail")
    @Loggable
    public BaseResult details(String combinationCode) {
        if (Strings.isNullOrEmpty(combinationCode)) {
            return BaseResult.success();
        }

        return BaseResult.success(fundCombinationService.queryByCombinationCode(combinationCode));
    }

    /**
     * 组合的交易详情
     *
     * @param combinationCode
     * @return
     */
    @Loggable
    @GetMapping("risk_detail")
    public BaseResult detail(HttpServletRequest request, @RequestParam String combinationCode) {
        if (Strings.isNullOrEmpty(combinationCode)) {
            return BaseResult.success();
        }
        Long userId = Long.valueOf(RequestUtils.getHeader(request, "userid"));
        return BaseResult.success(portfolioService.getTradeDetail(userId, combinationCode));
    }

    /**
     * 组合详情 收益图表 数据
     *
     * @param combinationCode
     * @param type
     * @return
     */
    @GetMapping("query_chart")
    @Loggable
    public BaseResult queryChart(String combinationCode, String type) {
        BaseResult result = new BaseResult();

        if (!Strings.isNullOrEmpty(combinationCode) && !Strings.isNullOrEmpty(type)) {
            result.setResult(fundCombinationHistoryService.queryByDate(type, combinationCode));
        }

        return result;
    }

    /**
     * 组合 当前调仓
     *
     * @param combinationCode
     * @return
     */
    @GetMapping("query_recent_transfer")
    @Loggable
    public BaseResult queryRecentTransfer(String combinationCode) {
        if (Strings.isNullOrEmpty(combinationCode)) {
            return BaseResult.success();
        }

        return BaseResult.success(fundWarehouseTransferService.queryRencentTransfer(combinationCode));
    }


    /**
     * 组合 调仓历史
     *
     * @param combinationCode
     * @return
     */
    @GetMapping("query_transfers")
    @Loggable
    public BaseResult queryTransfers(String combinationCode) {
        if (Strings.isNullOrEmpty(combinationCode)) {
            return BaseResult.success();
        }

        return BaseResult.success(fundWarehouseTransferService.queryTransfers(combinationCode));

    }

    /**
     * 组合交易记录
     *
     * @param requestNum
     * @param queryFlag
     * @param beginNum
     * @param sortDirection
     * @author mifj
     */
    @GetMapping("/record")
    @Loggable
    public com.codi.bus.core.resultModel.BaseResult record(@RequestParam Integer requestNum,
                                                           @RequestParam Integer queryFlag,
                                                           @RequestParam Integer beginNum,
                                                           @RequestParam String sortDirection, HttpServletRequest request) {
        PortfolioApplyListResult result = null;
        Long userId = Long.valueOf(RequestUtils.getHeader(request, "userid"));
        try {
            result = queryService.queryPortfolioApplys(userId, requestNum, queryFlag, beginNum, sortDirection, true);
        } catch (Exception e) {
            log.error("h5接口:/h5/portfolio/record 错误信息:{}", e.getMessage());
            e.printStackTrace();
        }
        assert result != null;
        if (!result.getSuccess() && StringUtil.isEmpty(result.getErrorMessage())) {
            result.setErrorMessage(MessageUtil.getErrorMessage(result.getErrorCode(), null));
        }
        return result;
    }

    /**
     * 组合分红交易记录
     */
    @GetMapping("/dividend/apply")
    @Loggable
    public com.codi.bus.core.resultModel.BaseResult dividendApply(@RequestParam Integer requestNum,
                                                                  @RequestParam Integer queryFlag,
                                                                  @RequestParam Integer beginNum,
                                                                  @RequestParam String sortDirection, HttpServletRequest request) {
        Long userId = Long.valueOf(RequestUtils.getHeader(request, "userid"));
        String taSerialId = null;
        DividendApplyResult result = dividendApplyQuery.queryPortfolioDividendApplys(userId, requestNum, queryFlag, beginNum,
            sortDirection, taSerialId);
        if (!result.getSuccess() && StringUtil.isEmpty(result.getErrorMessage())) {
            result.setErrorMessage(MessageUtil.getErrorMessage(result.getErrorCode(), null));
        }
        return result;

    }


    /**
     * 资产--组合交易记录
     * 要看 1.1.0的 代码   需要的话把这个类和 applyRecordService applyRecordServiceImpl 回滚到 5月21号
     * @param portfolioCode 组合代码 非必
     * @param queryType     业务类型, all 全部 onWay 进行中
     * @return
     */
    @GetMapping("/portfolioRecord")
    @Loggable
    public com.codi.bus.core.resultModel.BaseResult portfolioRecord(HttpServletRequest request, String portfolioCode, @NonNull String queryType, String business, Integer requestNum, Integer beginNum, String portfolioAllotNo) {
        PTradingRecordListResult pTradingRecordListResult = null;
        Long userId = Long.valueOf(RequestUtils.getHeader(request, "userid"));
        try {
            pTradingRecordListResult = applyRecordService.queryPortfolioRecord(portfolioCode, queryType, userId, beginNum, requestNum, business, portfolioAllotNo);
        } catch (Exception e) {
            ExceptionUtil.logError(log, "queryApplys - Exception:", e);
        }
        return pTradingRecordListResult;
    }


    @GetMapping("goBuy")
    @Loggable
    public BaseResult goBuy(HttpServletRequest request, @RequestParam String portfolioCode) {
        BaseResult result = new BaseResult();
        result.setSuccess(true);
        Map<String, Object> returnMap = Maps.newHashMap();
        Long userId = Long.valueOf(RequestUtils.getHeader(request, "userid"));
        try {
            com.codi.bus.core.resultModel.BaseResult payResult = paymentService.getPayMethodsForPortfolio(userId);
            if (!payResult.getSuccess()) {
                result.setSuccess(false);
                result.setErrorType(GlobalConstant.ERROR_TYPE_BUSINESS);
                result.setErrorCode(String.valueOf(ErrorConstant.ERROR_NO_ACCOUNT));
                result.setErrorMessage(MessageUtil.getErrorMsg(ErrorConstant.ERROR_NO_ACCOUNT));
                return result;
            }
            returnMap.put("payWay", payResult.getResult());
            com.codi.bus.core.resultModel.BaseResult portfolioResult = portfolioValidation.validateLimits(portfolioCode, GlobalConstant.CAPITAL_MODE_EPAY, "022");
            if (!portfolioResult.getSuccess()) {
                result.setSuccess(false);
                result.setErrorType(GlobalConstant.ERROR_TYPE_BUSINESS);
                result.setErrorCode(String.valueOf(portfolioResult.getErrorCode()));
                result.setErrorMessage(MessageUtil.getErrorMsg(portfolioResult.getErrorCode()));
                return result;
            }
            com.codi.bus.core.resultModel.BaseResult limitResult = portfolioService.getLimits(userId, portfolioCode, GlobalConstant.CAPITAL_MODE_EPAY, "022");
            if (!limitResult.getSuccess()) {
                result.setSuccess(false);
                result.setErrorType(GlobalConstant.ERROR_TYPE_BUSINESS);
                result.setErrorCode(String.valueOf(limitResult.getErrorCode()));
                result.setErrorMessage(MessageUtil.getErrorMsg(limitResult.getErrorCode()));
                return result;
            }
            returnMap.put("limits", limitResult.getResult());
        } catch (Exception e) {
            result.setSuccess(false);
            result.setErrorType(GlobalConstant.ERROR_TYPE_BUSINESS);
            result.setErrorCode(String.valueOf(ErrorConstant.ERROR_NO_ACCOUNT));
            result.setErrorMessage(MessageUtil.getErrorMsg(ErrorConstant.ERROR_NO_ACCOUNT));
            return result;
        }
        result.setResult(returnMap);
        return result;
    }

    /**
     * 组合--预估费用
     *
     * @param fundCodesStr 按组合下所有基金及基金占比，拼装每只基金购买金额，组装数据。如 ：110027|61.5|210002|61.5
     * @return
     * @throws BaseAppException
     */
    @GetMapping("estimateCost")
    @ResponseBody
    @Loggable
    public BaseResult estimateCost(HttpServletRequest request, @RequestParam String fundCodesStr) {
        Long userId = Long.valueOf(RequestUtils.getHeader(request, "userid"));
        BaseResult result = new BaseResult();
        result.setSuccess(true);
        result.setResult(portfolioService.getApplyRate(userId, fundCodesStr));
        return result;
    }

    /**
     * 组合--确认买入
     *
     * @param request
     * @param buyVo
     * @return
     */
    @PostMapping("/sureBuy")
    @Loggable
    public PortfolioTradeResult sureBuy(HttpServletRequest request, @Validated PortfolioTradeBuyVo buyVo) {
        Long userId = Long.valueOf(RequestUtils.getHeader(request, "userid"));
        String chanelCode = RequestUtils.getHeader(request, "channelCode");
        PortfolioTradeResult result = new PortfolioTradeResult();
        result.setSuccess(false);
        //组合只支持银行卡购买
        if (!EqualsUtil.equals(buyVo.getPayType(), PayTypeConst.BANK)) {
            result.setErrorCode(ErrorConst.COMMON_NOT_SUPPORT_PAY_TYPE);
            result.setErrorMessage(MessageUtil.getErrorMsg(ErrorConst.COMMON_NOT_SUPPORT_PAY_TYPE));
            return result;
        }
        // 验证是否重复提交, 5分钟过期
        String applyNo = buyVo.getApplyNo() + userId;
        String applyKey = CacheUtil.getKey(GlobalConstant.REDIS_KEY_APPLY_SELL, applyNo);
        if (!StringUtil.isEmpty(stringRedisTemplate.opsForValue().get(applyKey))) {
            result.setErrorType(GlobalConstant.ERROR_TYPE_APPLICATION);
            result.setErrorCode(ErrorConstant.ERROR_DUPLICATE_APPLY);
            result.setErrorMessage(MessageUtil.getErrorMessage(ErrorConstant.ERROR_DUPLICATE_APPLY, null));
            return result;
        }
        stringRedisTemplate.opsForValue().set(applyKey, applyNo, GlobalConstant.APPLY_EXPIRED_HOURS_DEFAULT, TimeUnit.HOURS);
        SessionVo sessionVo = new SessionVo();
        sessionVo.setUserId(userId)
            .setChannelId(chanelCode);
        return portfolioService.buy(sessionVo, buyVo);
    }

    /**
     * 组合--撤单
     *
     * @param request
     * @param undoVo
     * @return
     */
    @PostMapping("undo")
    @Loggable
    public com.codi.bus.core.resultModel.BaseResult undo(HttpServletRequest request, @Validated PortfolioTradeUndoVo undoVo) {
        Long userId = Long.valueOf(RequestUtils.getHeader(request, "userid"));
        String chanelCode = RequestUtils.getHeader(request, "channelCode");
        com.codi.bus.core.resultModel.BaseResult result = new com.codi.bus.core.resultModel.BaseResult();
        // 验证是否重复提交, 5分钟过期
        String applyNo = undoVo.getApplyNo() + userId;
        String applyKey = CacheUtil.getKey(GlobalConstant.REDIS_KEY_APPLY_SELL, applyNo);
        if (!StringUtil.isEmpty(stringRedisTemplate.opsForValue().get(applyKey))) {
            result.setErrorType(GlobalConstant.ERROR_TYPE_APPLICATION);
            result.setErrorCode(ErrorConstant.ERROR_DUPLICATE_APPLY);
            result.setErrorMessage(MessageUtil.getErrorMessage(ErrorConstant.ERROR_DUPLICATE_APPLY, null));
            return result;
        }
        stringRedisTemplate.opsForValue().set(applyKey, applyNo, GlobalConstant.APPLY_EXPIRED_HOURS_DEFAULT, TimeUnit.HOURS);
        SessionVo sessionVo = new SessionVo();
        sessionVo.setUserId(userId)
            .setChannelId(chanelCode);
        return portfolioService.undo(sessionVo, undoVo);
    }
}
